﻿#include "mainwindow.h"
#include "ui_mainwindow.h"

QTextCodec *ui_codec = QTextCodec::codecForName("gbk");


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->lineEdit_2->setText("192.168.12.175");
//    ui->lineEdit_2->setText("192.168.12.4");
    ui->lineEdit_3->setText("6153");
    ui->lineEdit_4->setText("6153");
    ui->lineEdit_5->setText("1");
    ui->lineEdit_6->setText("4096");
    sessionInfo.uMode = "udp";

    setComboBoxIp();
    //系统定时任务
    timer_id = startTimer(10);

//    QString ad = "C:/Users/屈雨江/Desktop/tr-Update-240108_1625.tar.bz2";
    QString tr = "C:/Users/Administrator/Desktop/tr-Update-231209_1633.tar.bz2";
    confBootloadData(tr);


}

MainWindow::~MainWindow()
{
    ui->pushButton_4->clicked();
    delete ui;
}

static QString toHexadecimal(const QByteArray &byteArray)
{
    QString str;
    for(int i = 0; i< byteArray.length(); i++){
        QString byteStr = QString::number(static_cast<uchar>(byteArray[i]), 16);
        if(byteStr.length() == 1) str += "0x0" + byteStr + " ";
        else str += "0x" + byteStr + " ";
    }
    return str;
}

//网络连接
void MainWindow::on_pushButton_2_clicked()
{
    sessionInfo.uSendAddr = ui->lineEdit_2->text();
    sessionInfo.uLocalAddr = ui->comboBox_2->currentText();
    QString a = ui->lineEdit_3->text();
    sessionInfo.uSendPort = a.toInt();
    QString c = ui->lineEdit_4->text();
    sessionInfo.uLocalPort = c.toInt();
    if(sessionInfo.uMode == "tcpClient") {
        tcpClientInit(sessionInfo.uSendAddr,sessionInfo.uSendPort);
    } else if (sessionInfo.uMode == "tcpServer") {
        tcpServerInit(sessionInfo.uLocalAddr,sessionInfo.uLocalPort);
    } else {
        udpInit(sessionInfo.uLocalAddr,sessionInfo.uLocalPort);
    }

    if(webConnect) {
        ui->pushButton_2->setEnabled(false);
        ui->pushButton_4->setEnabled(true);
    }

}
//网络断开
void MainWindow::on_pushButton_4_clicked()
{
    ui->pushButton_2->setEnabled(true);
    ui->pushButton_4->setEnabled(false);
    webConnect = false;
    if(udpSend != nullptr) {
        udpSend->close();
        udpSend->deleteLater();
    }
    if(udpRev != nullptr) {
        udpRev->close();
        udpRev->deleteLater();
    }
    if(mTcpSocket != nullptr) {
        mTcpSocket->close();
        mTcpSocket->deleteLater();
    }
    if(mTcpServe != nullptr) {
        mTcpServe->disconnect();
        mTcpServe->close();
        mTcpServe->deleteLater();
    }
}
//固件选择
void MainWindow::on_pushButton_clicked()
{
    QString path = QFileDialog::getOpenFileName(this, "open log file",
                                             "/",
                                             "file (*.bin *.bz2) ;;All (*.*)");
    confBootloadData(path);
}
void MainWindow::confBootloadData(QString path)
{
    QFile readfile(path);    //要读取的bin文件
    QFileInfo read_file_info(readfile);         //要读取的bin文件的信息
    if (!readfile.open(QIODevice::ReadOnly)) {  //只读方式打开bin文件
        ui->textEdit->append(("固件读取失败，请检查文件是否存在或占用!\r\n"));
        return;
    }
    ui->lineEdit->setText(path);

    networkBootloaderStruct.uPackageName = read_file_info.fileName();

    networkBootloaderStruct.uWingsCache.resize(read_file_info.size());
    networkBootloaderStruct.uWingsCache = readfile.readAll();
    ui->textEdit->append("提取到固件数据:"+
                                       QString::number(read_file_info.size())+
                                       ("字节"));
    networkBootloaderStruct.uDataSize = read_file_info.size();
    networkBootloaderStruct.uCrc32 = crc32((unsigned char *)networkBootloaderStruct.uWingsCache.data(),networkBootloaderStruct.uDataSize);
//    networkBootloaderStruct.uSendAddr = ui->lineEdit_2->text().toUInt();
    ui->textEdit->append(("固件校验和:0x")+
                         QString::number(networkBootloaderStruct.uCrc32,16));
    ui->label->setText("0/"+QString::number(networkBootloaderStruct.uDataSize));
    ui->progressBar->setValue(0);
}

//查询版本
void MainWindow::on_pushButton_3_clicked()
{
    if(webConnect) {
        bootloadSend.uHeader = WINGQUERY;
        bootloadSend.uType = ui->lineEdit_5->text().toUInt(); //获取组件ID
        bootloadSend.uTail = WINGTAIL;
        bootloadSend.uSize = 0;//crc32+长度+包名
        bootloadSend.uCrc32 = 0;
        if(sessionInfo.uMode == "udp") {
            firwareSendto(&bootloadSend);
        } else {
//            tcpWrite(&bootloadSend);
        }
    }
}
//清空S
void MainWindow::on_pushButton_5_clicked()
{
    ui->textEdit->clear();
}

//UDP/TCP下拉触发
void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1)
{
    //将当前选项名赋值给变量str，输出当前选项名
        sessionInfo.uMode = ui->comboBox->currentText();
        setComboBoxIp();
        ui->textEdit->append(("TCP未实现,不可用..."));
}

//固件更新
void MainWindow::on_pushButton_6_clicked()
{
    networkBootloaderStruct.uSubPackageSize = ui->lineEdit_6->text().toUInt();//取出分包设置的值
    networkBootloaderStruct.uType = ui->lineEdit_5->text().toInt();
    if(webConnect) {
        ui->progressBar->setRange(0,networkBootloaderStruct.uDataSize);
        bootloadSend.uHeader = WINGSTART;
        bootloadSend.uType = networkBootloaderStruct.uType; //获取组件ID
        bootloadSend.uTail = WINGTAIL;
        bootloadSend.uSize = 4 + 4 + networkBootloaderStruct.uPackageName.size();//crc32+长度+包名
        memcpy(bootloadSend.uFirware,(uint8_t *)&networkBootloaderStruct.uDataSize,4);
        memcpy(&bootloadSend.uFirware[4],(uint8_t *)&networkBootloaderStruct.uCrc32,4);
        QByteArray ba = networkBootloaderStruct.uPackageName.toLatin1();
        memcpy(&bootloadSend.uFirware[8], ba.data(),ba.size());
        if(sessionInfo.uMode == "udp") {
            firwareSendto(&bootloadSend);
            ui->textEdit->append(("正在与目标固件握手..."));
        } else {
//            tcpWrite(array_data);
        }
    }
}

qint64 MainWindow::firwareSendto(struct cmdStruct *cmd)
{
    qint8 cmdLen = 20;
    qint64 ret = 0;
    uint32_t uCrc32 = 0;
    if(cmd->uSize != 0) {
        uCrc32 = crc32( (unsigned char *)cmd->uFirware,(cmd->uSize));//数据实体校验
    }

    cmd->uCrc32 = uCrc32;
    ret = splitData(sessionInfo.uSendAddr,sessionInfo.uSendPort,(unsigned char *)cmd,cmdLen);
    if(cmd->uSize != 0) {
       ret += splitData(sessionInfo.uSendAddr,sessionInfo.uSendPort,(unsigned char *)(cmd->uFirware),(cmd->uSize));
    }
    return ret;
}

void MainWindow::setComboBoxIp()
{
    checkNetwork();
    ui->comboBox_2->clear();
    ui->comboBox_2->addItems(ipAddressList);
}

void MainWindow::setProgressBar(uint32_t val)
{
    ui->progressBar->setValue(val+1);
    ui->label->setText(QString::number(val) + "/"+QString::number(networkBootloaderStruct.uDataSize));
}

void MainWindow::checkNetwork()
{
    bool ethernetIpOk = false;
    bool wlanIpOk = false;

    QList<QNetworkInterface> networkInterfaces = QNetworkInterface::allInterfaces();
    ipAddressList.clear();
    for (int i = 0; i < networkInterfaces.size(); i++)
    {
        QString hardwareAddress = networkInterfaces[i].hardwareAddress();
        QString readableName = networkInterfaces[i].humanReadableName();
        QString interfaceName = networkInterfaces[i].interfaceNameFromIndex(i);
        QString adapterName = networkInterfaces[i].name();

        QList<QNetworkAddressEntry> addressEntryList = networkInterfaces[i].addressEntries();

        for (int j = 0; j < addressEntryList.size(); j++)
        {
            QString ipAddress = addressEntryList[j].ip().toString();
            QString ipMask = addressEntryList[j].netmask().toString();

            if (adapterName.contains("ethernet"))
            {
                QStringList ipList = ipAddress.split('.');
                if (ipList.size() < 4)
                    continue;

                if (ipAddress.contains("192.168."))
                {
                    ipAddressList << ipAddress;
                    ethernetIpOk = true;
                    ui->textEdit->append("Info: Locl ethernet ip is " + ipAddress);
                }
            }
            else if (adapterName.contains("wireless"))
            {
                QStringList ipList = ipAddress.split('.');
                if (ipList.size() < 4)
                    continue;

                if (ipAddress.contains("192.168."))
                {
                    ipAddressList << ipAddress;
                    wlanIpOk = true;
                    ui->textEdit->append(("Info: Locl wireless ip is ") + ipAddress);
                }
            }
        }
    }

    if (!ethernetIpOk)
    {
        ui->textEdit->append(("Warning: Wired IP address isn't in range of 192.168.0.xxx."));
    }

    if (!wlanIpOk)
    {
        ui->textEdit->append(("Warning: Wireless IP address isn't in range of 192.168.0.xxx."));
    }
}


qint64 MainWindow::udpWrite(QString remoteIp,qint64 remotePort,QByteArray sMsg)
{
    QByteArray msg;
    msg = sMsg;

    udpSend->close();
    udpSend->open(QIODevice::ReadWrite);
    udpSend->bind(remotePort,QAbstractSocket::BindFlag::ReuseAddressHint);//指定发送端口
    return udpSend->writeDatagram(msg,QHostAddress(remoteIp),remotePort);//目标IP端口
}

void MainWindow::slotReadDatagrams()
{
    while(udpRev->hasPendingDatagrams())
    {
        mReciver.msg.clear();
        mReciver.msg.resize(udpRev->pendingDatagramSize());
        udpRev->readDatagram(mReciver.msg.data(),mReciver.msg.size(),&mReciver.ip,&mReciver.port);
        if (ui->checkBox->isChecked()) {
//            QString str = ;
            ui->textEdit->append(("udp收: ") + toHexadecimal(mReciver.msg));
        } else {
            ui->textEdit->append(("udp收: ") + QString(mReciver.msg));
        }


        udpQueue.enqueue(mReciver.msg);
    }
}

void MainWindow::udpInit(QString localIp,qint64 localPort)
{
    udpSend = new QUdpSocket();
    udpRev = new QUdpSocket();



    //第一个参数是服务端绑定的地址,第二个参数是接收消息的端口号
    bool state = false;

    state =  udpRev->bind(QHostAddress(localIp), localPort, QAbstractSocket::BindFlag::ReuseAddressHint);
    //连接套接字,若有客户端发消息过来,则会触发槽函数
    connect(udpRev,SIGNAL(readyRead()),this,SLOT(slotReadDatagrams()), Qt::DirectConnection);
    webConnect = state;
    udpQueue.clear();
    if(state == false)
    {
        ui->textEdit->append(("打开失败"));
        udpRev->abort();
        udpRev->disconnectFromHost();
    }

}

#define UDP_BLOCK_SIZE (1480)
unsigned char frameBuffer[UDP_BLOCK_SIZE];
int MainWindow::splitData(QString remoteIp,qint64 remotePort,unsigned char* msg,quint64 nLen)
{
    int nBlockNum = nLen / UDP_BLOCK_SIZE;
    int poayload_size = 0;
    unsigned char* pBuff = msg;
    unsigned char *payload = nullptr;
    if (nLen % UDP_BLOCK_SIZE != 0)
    {
        nBlockNum++;
    }
    qint64 sendlen = 0;

    udpSend->close();
    udpSend->open(QIODevice::ReadWrite);
    auto bindFlag = udpSend->bind(remotePort,QAbstractSocket::BindFlag::ReuseAddressHint);//指定发送端口
    if(!bindFlag) {
        udpSend->close();
        ui->textEdit->append(("绑定失败"));
        return 0;
    }

    for (int i = 0; i < nBlockNum; i++)
    {
        memset(frameBuffer,0,UDP_BLOCK_SIZE);
        //每次发送udp最大字节
        poayload_size = UDP_BLOCK_SIZE;
        payload = pBuff + UDP_BLOCK_SIZE * (i);
        //如果当前剩余的udp数据长度不满最大长度
        if (nLen - UDP_BLOCK_SIZE * (i) < UDP_BLOCK_SIZE)
            poayload_size = nLen - (UDP_BLOCK_SIZE * (i));

        memcpy(frameBuffer,payload,poayload_size);
        qint64 ret = udpSend->writeDatagram((const char*)frameBuffer,poayload_size,QHostAddress(remoteIp),remotePort);//目标IP端口
        sendlen += ret;
        sleep(5);//延迟5ms
    }
    return sendlen;
}

//延时功能
void MainWindow::sleep(unsigned int msec){
//currnentTime 返回当前时间 用当前时间加上我们要延时的时间msec得到一个新的时刻
    QTime reachTime = QTime::currentTime().addMSecs(msec);
    //用while循环不断比对当前时间与我们设定的时间
    while(QTime::currentTime()<reachTime){
    //如果当前的系统时间尚未达到我们设定的时刻，就让Qt的应用程序类执行默认的处理，
    //以使程序仍处于响应状态。一旦到达了我们设定的时刻，就跳出该循环，继续执行后面的语句。
        QApplication::processEvents(QEventLoop::AllEvents,100);
    }
}

/************************************TCPClient*******************************************/
void MainWindow::tcpClientInit(QString remoteIp,qint64 remotePort)
{
    mTcpSocket = new QTcpSocket( ); // 在这里使用this作为父对象，确保在窗口关闭时自动释放资源

    connect(mTcpSocket, &QTcpSocket::connected, this, &MainWindow::onConnected);
    connect(mTcpSocket, &QTcpSocket::disconnected, this, &MainWindow::onDisConnected);
    connect(mTcpSocket, &QTcpSocket::stateChanged, this, &MainWindow::onStateChanged);
    connect(mTcpSocket, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);
    connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));

    mTcpSocket->connectToHost(remoteIp, remotePort);//连接服务端
    webConnect = true;
}

void MainWindow::tcpWrite(QByteArray sMsg)
{
    QByteArray msg;
    msg = sMsg;

    mTcpSocket->write(msg);
}

void MainWindow::tcpDisconnect()
{
    if(mTcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        mTcpSocket->disconnectFromHost();
        webConnect = false;
    }
}

void MainWindow::onConnected()
{
    ui->textEdit->append(("已连接到服务器)"));
    ui->textEdit->append(("设备IP: ")+mTcpSocket->peerAddress().toString());
    ui->textEdit->append(("设备端口: ")+QString::number(mTcpSocket->peerPort()));
}

void MainWindow::onDisConnected()
{
    //ui->textEdit->append(("已断开服务器"));
}

void MainWindow::onStateChanged(QAbstractSocket::SocketState)
{

}

void MainWindow::displayError(QAbstractSocket::SocketError socketError)
{
    switch (socketError) {
    case QAbstractSocket::RemoteHostClosedError:
        ui->textEdit->append(("远程主机关闭了连接"));
        break;
    case QAbstractSocket::HostNotFoundError:
        ui->textEdit->append(("找不到主机"));
        break;
    case QAbstractSocket::ConnectionRefusedError:
        ui->textEdit->append(("该连接被对等方拒绝"));
        break;
    default:
        ui->textEdit->append(("出现以下错误: ") + mTcpSocket->errorString());
    }
}
//1、QByteArray转QString
//QByteArray Data;
//QString str = QString(Data);

//2、QString转QByteArray
//QByteArray by1 = str.toLatin1();
//QByteArray by2 = str.toLocal8Bit();

void MainWindow::onReadyRead()
{
    QByteArray msg = mTcpSocket->readAll();
    ui->textEdit->append(("tcp: ") + QString(msg));
//    tcpQueue.enqueue(msg);
}

/*****************************TCP SERVER***************************************/

void MainWindow::tcpServerInit(QString remoteIp,qint64 remotePort)
{
    mTcpServe=new QTcpServer(this);
    //服务端监听客户端发来的请求
    if(!mTcpServe->listen(QHostAddress::AnyIPv4,remotePort)){
        qDebug()<<mTcpServe->errorString();
        close();
    }
    connect(mTcpServe,&QTcpServer::newConnection,this,&MainWindow::onNewConnect);
    connect(mTcpServe,&QTcpServer::newConnection,this,&MainWindow::onSendBackMsg);
    webConnect = true;
}



void MainWindow::onNewConnect()
{
    //当前连接的客户端
    mTcpSocket=mTcpServe->nextPendingConnection();
    //断开连接
    connect(mTcpSocket,&QTcpSocket::disconnected,
            mTcpSocket,&QTcpSocket::deleteLater);
    //socket有数据时会发送readyRead信号
    connect(mTcpSocket,&QTcpSocket::readyRead,
            this,&MainWindow::onReadMsg);
}

void MainWindow::onSendBackMsg()
{
    QString str="你好，客户端！";
    mTcpSocket->write(str.toUtf8());
}

void MainWindow::onReadMsg()
{
    //服务端将客户端发来的数据显示到标签上
    QByteArray bt=mTcpSocket->readAll();
    ui->textEdit->append(("tcp: ") + QString(bt));
}



